<template>
  <div :class="formItemCls">
    <div v-if="showLabel" :class="dynamicCls" class="form-item-label-width relative-position">
        <span :class="spanCls">
          <i v-if="column.required" class="absolute required-asterisk-cls text-red text-weight-bold">*</i>
          <template v-if="isSlot(`${column.field}H`)">
            <slot :column="column" :name="column.field + 'H'"></slot>
          </template>

          <template v-else>
            <q-icon v-if="column.tips" class="cursor-pointer label-help" color="grey-6" name="help" size=".95rem">
              <q-tooltip v-bind="$tooltipAttr" v-bind:maxWidth="'18rem'">{{ column.tips }}</q-tooltip>
            </q-icon>
            {{ column.label }}
          </template>
        </span>
    </div>
    <q-item-section class="qx-form-item-card">
      <template v-if="column.formslot">
        <slot :attrs="{ ...attrs, dense: isDense }" :name="column.field"></slot>
      </template>
      <template v-else>
        <component :is="getComponent(column)" v-model="formInfo[column.field]" :dense="isDense" :isSearch="isSearch"
                   :loading="loading" :readonly="loading || readonly" name v-bind="attrs">
          <template v-if="isSlot(`${column.field}B`)" v-slot:before>
            <slot :name="column.field + 'B'"></slot>
          </template>
          <template v-if="isSlot(`${column.field}A`)" v-slot:after>
            <slot :name="column.field + 'A'"></slot>
          </template>
          <template v-if="isSlot(`${column.field}P`)" v-slot:prepend>
            <slot :name="column.field + 'P'"></slot>
          </template>
          <template v-if="isSlot(`${column.field}AP`)" v-slot:append>
            <slot :name="column.field + 'AP'"></slot>
          </template>
        </component>
      </template>
    </q-item-section>
  </div>
</template>

<script setup>
import { getAttrs, getComponent } from 'components/formUtils'
import { isEmpty } from 'src/utils/utils'
import { computed, inject, useSlots, watch } from 'vue'

const props = defineProps({
  column: { type: Object, default: () => ({}) }, dense: { type: Boolean, default: true },
  isAuto: Boolean, nonTop: Boolean, loading: Boolean, readonly: Boolean, isSearch: Boolean, formWidth: Number,
  labelPosition: String, span: [String, Number], labelWidth: [String, Number]
})

const formInfo = defineModel('modelValue', { type: Object, default: () => ({}) })
const isDense = computed(() => props.dense ?? inject('isDense', true))
const dynamicCol = computed(() => {
  if (props.isSearch) return props.span || 6
  if (!props.formWidth) return props.span || 12
  if (props.span) return props.isAuto && [24, '24'].includes(props.span) && props.formWidth > 2000 ? 12 : props.span
  let col = 3
  if (props.formWidth < 401) col = 24
  else if (props.formWidth < 801) col = 12
  else if (props.formWidth < 1201) col = 8
  else if (props.formWidth < 1801) col = 6
  else if (props.formWidth < 3601) col = 4
  return props.span > col ? props.span : col
})
const isTop = computed(() => {
  if (props.nonTop) return false
  if (!props.isSearch && props.formWidth && (props.formWidth / 24 * dynamicCol.value) < 301) return true
  return props.labelPosition === 'top'
})
const spanCls = computed(() => {
  let cls = 'relative-position'
  if (isTop.value) cls += ' ellipsis'
  else cls += ' ellipsis-2-lines'
  if (props.column?.required) cls += ' q-pl-sm'
  return cls
})
const formItemCls = computed(() => {
  const { classes = '' } = props.column
  let cls = `${classes} qx-form-item items-start`
  if (!isTop.value) cls += ' row no-wrap'
  return `${cls} q-col-${dynamicCol.value}`
})
const dynamicCls = computed(() => {
  const { headerClasses = '' } = props.column
  let cls = `${headerClasses} q-pr-sm row items-center`
  if (isDense.value) cls += ' qx-form-item-label-dense'
  else cls += ' qx-form-item-label'
  if (isTop.value) cls += ' qx-form-item-label-top'
  else if (props.labelPosition === 'left') cls += ' justify-start text-left'
  else cls += ' justify-end text-right'
  return cls
})
const SLOTS = Object.keys(useSlots())
const isSlot = computed(() => field => SLOTS.includes(field))
const showLabel = computed(() => !['0', 0].includes(props.labelWidth))
const columnLW = computed(() => {
  if (isTop.value || !showLabel.value) return '100%'
  if (props.formWidth && (props.formWidth / 24 * dynamicCol.value) < 180) return '18px'
  return `${props.labelWidth || 80}px`
})
const attrs = computed(() => {
  const attrs = getAttrs(props.column, formInfo.value, props.isSearch)
  attrs.loading = attrs.loading || props.loading
  return attrs
})

const initForm = (val, oldVal) => {
  const { field } = props.column || {}
  if (!field) return
  if (!isEmpty(oldVal) && formInfo.value[field] === oldVal) return (formInfo.value[field] = val)
  if (!isEmpty(formInfo.value[field]) || isEmpty(val)) return
  formInfo.value[field] = val
}

watch(() => props.column?.value, (val, oldVal) => initForm(val, oldVal), { immediate: true })
</script>

<style lang="scss" scoped>
.form-item-label-width {
  width: v-bind(columnLW);

  .label-help {
    top: -.05rem;
    position: relative;
  }
}

.required-asterisk-cls {
  transform: translateX(-0.5rem);
}
</style>